import time
from common import (
    lib60870,
    CS104_Slave, TLSConfiguration, IMasterConnection, CS101_ASDU, CP56Time2a,
    CS104_PeerConnectionEvent,
    CS101_InterrogationHandler, CS101_ClockSynchronizationHandler,
    CS104_ConnectionRequestHandler, CS104_ConnectionEventHandler,
    CS101_ASDUHandler
)
from ctypes import c_void_p, c_int, c_uint8, c_bool, c_char_p, POINTER, Structure, c_uint16, c_uint32

# 补充必要的常量定义
CS101_COT_INTERROGATED_BY_STATION = 20
CS101_COT_ACTIVATION = 3
CS101_COT_ACTIVATION_CON = 4
CS101_COT_UNKNOWN_IOA = 10
CS101_COT_UNKNOWN_COT = 11
CS101_COT_PERIODIC = 1
IEC60870_QUALITY_GOOD = 0
C_SC_NA_1 = 21
CS104_MODE_SINGLE_REDUNDANCY_GROUP = 1

# 补充信息对象和ASDU操作函数封装
lib60870.CS104_Slave_getAppLayerParameters.restype = POINTER(Structure)
lib60870.CS104_Slave_getAppLayerParameters.argtypes = [CS104_Slave]

lib60870.IMasterConnection_getApplicationLayerParameters.restype = POINTER(Structure)
lib60870.IMasterConnection_getApplicationLayerParameters.argtypes = [IMasterConnection]

lib60870.CS101_ASDU_create.restype = CS101_ASDU
lib60870.CS101_ASDU_create.argtypes = [POINTER(Structure), c_bool, c_int, c_int, c_int, c_bool, c_bool]

lib60870.CS101_ASDU_addInformationObject.restype = c_bool
lib60870.CS101_ASDU_addInformationObject.argtypes = [CS101_ASDU, c_void_p]

lib60870.CS101_ASDU_destroy.restype = None
lib60870.CS101_ASDU_destroy.argtypes = [CS101_ASDU]

lib60870.CS101_ASDU_getTypeID.restype = c_int
lib60870.CS101_ASDU_getTypeID.argtypes = [CS101_ASDU]

lib60870.CS101_ASDU_getCOT.restype = c_int
lib60870.CS101_ASDU_getCOT.argtypes = [CS101_ASDU]

lib60870.CS101_ASDU_setCOT.restype = None
lib60870.CS101_ASDU_setCOT.argtypes = [CS101_ASDU, c_int]

lib60870.CS101_ASDU_getElement.restype = c_void_p
lib60870.CS101_ASDU_getElement.argtypes = [CS101_ASDU, c_int]

lib60870.InformationObject_getObjectAddress.restype = c_int
lib60870.InformationObject_getObjectAddress.argtypes = [c_void_p]

lib60870.InformationObject_destroy.restype = None
lib60870.InformationObject_destroy.argtypes = [c_void_p]

lib60870.MeasuredValueScaled_create.restype = c_void_p
lib60870.MeasuredValueScaled_create.argtypes = [c_void_p, c_int, c_int16, c_int]

lib60870.SinglePointInformation_create.restype = c_void_p
lib60870.SinglePointInformation_create.argtypes = [c_void_p, c_int, c_bool, c_int]

lib60870.BitString32_create.restype = c_void_p
lib60870.BitString32_create.argtypes = [c_void_p, c_int, c_uint32]

lib60870.SingleCommand_getState.restype = c_bool
lib60870.SingleCommand_getState.argtypes = [c_void_p]

lib60870.IMasterConnection_sendACT_TERM.restype = c_bool
lib60870.IMasterConnection_sendACT_TERM.argtypes = [IMasterConnection, CS101_ASDU]

lib60870.CS104_Slave_setASDUHandler.restype = None
lib60870.CS104_Slave_setASDUHandler.argtypes = [CS104_Slave, CS101_ASDUHandler, c_void_p]

lib60870.CS104_Slave_enqueueASDU.restype = c_bool
lib60870.CS104_Slave_enqueueASDU.argtypes = [CS104_Slave, CS101_ASDU]

lib60870.CS104_Slave_setServerMode.restype = None
lib60870.CS104_Slave_setServerMode.argtypes = [CS104_Slave, c_int]

lib60870.CS104_Slave_isRunning.restype = c_bool
lib60870.CS104_Slave_isRunning.argtypes = [CS104_Slave]

lib60870.CP56Time2a_getHour.restype = c_int
lib60870.CP56Time2a_getHour.argtypes = [CP56Time2a]

lib60870.CP56Time2a_getMinute.restype = c_int
lib60870.CP56Time2a_getMinute.argtypes = [CP56Time2a]

lib60870.CP56Time2a_getSecond.restype = c_int
lib60870.CP56Time2a_getSecond.argtypes = [CP56Time2a]

lib60870.CP56Time2a_getDayOfMonth.restype = c_int
lib60870.CP56Time2a_getDayOfMonth.argtypes = [CP56Time2a]

lib60870.CP56Time2a_getMonth.restype = c_int
lib60870.CP56Time2a_getMonth.argtypes = [CP56Time2a]

lib60870.CP56Time2a_getYear.restype = c_int
lib60870.CP56Time2a_getYear.argtypes = [CP56Time2a]

# 从站高级封装类
class CS104Slave:
    def __init__(self, max_low_prio_queue_size, max_high_prio_queue_size, tls_config=None):
        if tls_config:
            self.slave = lib60870.CS104_Slave_createSecure(
                max_low_prio_queue_size, max_high_prio_queue_size, tls_config)
        else:
            self.slave = lib60870.CS104_Slave_create(
                max_low_prio_queue_size, max_high_prio_queue_size)
        
        self.interrogation_handler = None
        self.clock_sync_handler = None
        self.connection_request_handler = None
        self.connection_event_handler = None
        self.asdu_handler = None
        self.al_params = lib60870.CS104_Slave_getAppLayerParameters(self.slave)
        self.scaled_value = 0  # 用于周期性发送的测量值

    def set_local_address(self, ip_address):
        lib60870.CS104_Slave_setLocalAddress(self.slave, ip_address.encode('utf-8'))

    def set_local_port(self, port):
        lib60870.CS104_Slave_setLocalPort(self.slave, port)

    def start(self):
        lib60870.CS104_Slave_start(self.slave)

    def stop(self):
        lib60870.CS104_Slave_stop(self.slave)

    def set_interrogation_handler(self, handler):
        self.interrogation_handler = CS101_InterrogationHandler(handler)
        lib60870.CS104_Slave_setInterrogationHandler(
            self.slave, self.interrogation_handler, None)

    def set_clock_sync_handler(self, handler):
        self.clock_sync_handler = CS101_ClockSynchronizationHandler(handler)
        lib60870.CS104_Slave_setClockSyncHandler(
            self.slave, self.clock_sync_handler, None)

    def set_connection_request_handler(self, handler):
        self.connection_request_handler = CS104_ConnectionRequestHandler(handler)
        lib60870.CS104_Slave_setConnectionRequestHandler(
            self.slave, self.connection_request_handler, None)

    def set_connection_event_handler(self, handler):
        self.connection_event_handler = CS104_ConnectionEventHandler(handler)
        lib60870.CS104_Slave_setConnectionEventHandler(
            self.slave, self.connection_event_handler, None)

    def set_asdu_handler(self, handler):
        self.asdu_handler = CS101_ASDUHandler(handler)
        lib60870.CS104_Slave_setASDUHandler(
            self.slave, self.asdu_handler, None)

    def set_server_mode(self, mode):
        lib60870.CS104_Slave_setServerMode(self.slave, mode)

    def is_running(self):
        return lib60870.CS104_Slave_isRunning(self.slave)

    def enqueue_asdu(self, asdu):
        return lib60870.CS104_Slave_enqueueASDU(self.slave, asdu)


# 辅助函数：打印CP56Time2a时间
def print_cp56time2a(time):
    hour = lib60870.CP56Time2a_getHour(time)
    minute = lib60870.CP56Time2a_getMinute(time)
    second = lib60870.CP56Time2a_getSecond(time)
    day = lib60870.CP56Time2a_getDayOfMonth(time)
    month = lib60870.CP56Time2a_getMonth(time)
    year = lib60870.CP56Time2a_getYear(time) + 2000
    print(f"{hour:02d}:{minute:02d}:{second:02d} {day:02d}/{month:02d}/{year}")


# 使用示例
def example_usage():
    # 创建从站实例
    slave = CS104Slave(10, 10)
    
    # 设置本地地址和端口
    slave.set_local_address("0.0.0.0")
    slave.set_local_port(2404)
    slave.set_server_mode(CS104_MODE_SINGLE_REDUNDANCY_GROUP)
    
    # 定义回调函数
    def interrogation_handler(parameter, connection, asdu, qoi):
        print(f"Received interrogation for group {qoi}")
        
        if qoi == 20:  # 处理站询问
            al_params = lib60870.IMasterConnection_getApplicationLayerParameters(connection)
            lib60870.IMasterConnection_sendACT_CON(connection, asdu, False)

            # 发送带MeasuredValueScaled的ASDU
            new_asdu = lib60870.CS101_ASDU_create(
                al_params, False, CS101_COT_INTERROGATED_BY_STATION, 0, 1, False, False)
            io = lib60870.MeasuredValueScaled_create(None, 100, -1, IEC60870_QUALITY_GOOD)
            lib60870.CS101_ASDU_addInformationObject(new_asdu, io)
            lib60870.CS101_ASDU_addInformationObject(new_asdu, 
                lib60870.MeasuredValueScaled_create(io, 101, 23, IEC60870_QUALITY_GOOD))
            lib60870.CS101_ASDU_addInformationObject(new_asdu, 
                lib60870.MeasuredValueScaled_create(io, 102, 2300, IEC60870_QUALITY_GOOD))
            lib60870.InformationObject_destroy(io)
            lib60870.IMasterConnection_sendASDU(connection, new_asdu)
            lib60870.CS101_ASDU_destroy(new_asdu)

            # 发送带SinglePointInformation的ASDU
            new_asdu = lib60870.CS101_ASDU_create(
                al_params, False, CS101_COT_INTERROGATED_BY_STATION, 0, 1, False, False)
            io = lib60870.SinglePointInformation_create(None, 104, True, IEC60870_QUALITY_GOOD)
            lib60870.CS101_ASDU_addInformationObject(new_asdu, io)
            lib60870.CS101_ASDU_addInformationObject(new_asdu,
                lib60870.SinglePointInformation_create(io, 105, False, IEC60870_QUALITY_GOOD))
            lib60870.InformationObject_destroy(io)
            lib60870.IMasterConnection_sendASDU(connection, new_asdu)
            lib60870.CS101_ASDU_destroy(new_asdu)

            # 发送带多个SinglePointInformation的ASDU
            new_asdu = lib60870.CS101_ASDU_create(
                al_params, True, CS101_COT_INTERROGATED_BY_STATION, 0, 1, False, False)
            io = lib60870.SinglePointInformation_create(None, 300, True, IEC60870_QUALITY_GOOD)
            for i in range(301, 308):
                lib60870.CS101_ASDU_addInformationObject(new_asdu,
                    lib60870.SinglePointInformation_create(io, i, i%2==0, IEC60870_QUALITY_GOOD))
            lib60870.InformationObject_destroy(io)
            lib60870.IMasterConnection_sendASDU(connection, new_asdu)
            lib60870.CS101_ASDU_destroy(new_asdu)

            # 发送带BitString32的ASDU
            new_asdu = lib60870.CS101_ASDU_create(
                al_params, False, CS101_COT_INTERROGATED_BY_STATION, 0, 1, False, False)
            io = lib60870.BitString32_create(None, 500, 0xaaaa)
            lib60870.CS101_ASDU_addInformationObject(new_asdu, io)
            lib60870.InformationObject_destroy(io)
            lib60870.IMasterConnection_sendASDU(connection, new_asdu)
            lib60870.CS101_ASDU_destroy(new_asdu)

            lib60870.IMasterConnection_sendACT_TERM(connection, asdu)
        else:
            lib60870.IMasterConnection_sendACT_CON(connection, asdu, True)
        return True
    
    def clock_sync_handler(parameter, connection, asdu, new_time):
        print("Process time sync command with time ", end="")
        print_cp56time2a(new_time)
        # 设置响应时间戳（此处简化处理）
        lib60870.IMasterConnection_sendACT_CON(connection, asdu, False)
        return True
    
    def connection_request_handler(parameter, ip_address):
        ip = ip_address.decode('utf-8')
        print(f"New connection request from {ip}")
        return True  # 接受所有连接
    
    def connection_event_handler(parameter, connection, event):
        event_map = {
            CS104_PeerConnectionEvent.CS104_CON_EVENT_CONNECTION_OPENED: "Connection opened",
            CS104_PeerConnectionEvent.CS104_CON_EVENT_CONNECTION_CLOSED: "Connection closed",
            CS104_PeerConnectionEvent.CS104_CON_EVENT_ACTIVATED: "Connection activated",
            CS104_PeerConnectionEvent.CS104_CON_EVENT_DEACTIVATED: "Connection deactivated"
        }
        print(f"{event_map.get(event, f'Unknown event {event}')} ({connection})")
    
    def asdu_handler(parameter, connection, asdu):
        if lib60870.CS101_ASDU_getTypeID(asdu) == C_SC_NA_1:
            print("Received single command")
            cot = lib60870.CS101_ASDU_getCOT(asdu)
            
            if cot == CS101_COT_ACTIVATION:
                io = lib60870.CS101_ASDU_getElement(asdu, 0)
                if io:
                    ioa = lib60870.InformationObject_getObjectAddress(io)
                    if ioa == 5000:
                        state = lib60870.SingleCommand_getState(io)
                        print(f"IOA: {ioa} switch to {state}")
                        lib60870.CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON)
                    else:
                        lib60870.CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_IOA)
                    lib60870.InformationObject_destroy(io)
                else:
                    print("ERROR: message has no valid information object")
                    return True
            else:
                lib60870.CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT)
            
            lib60870.IMasterConnection_sendASDU(connection, asdu)
            return True
        return False
    
    # 设置回调函数
    slave.set_interrogation_handler(interrogation_handler)
    slave.set_clock_sync_handler(clock_sync_handler)
    slave.set_connection_request_handler(connection_request_handler)
    slave.set_connection_event_handler(connection_event_handler)
    slave.set_asdu_handler(asdu_handler)
    
    # 启动从站
    slave.start()
    if not slave.is_running():
        print("Starting server failed!")
        return
    
    print("CS104 slave started. Press Ctrl+C to stop.")
    
    # 运行主循环，周期性发送数据
    try:
        while True:
            time.sleep(1)
            # 创建周期性发送的ASDU
            new_asdu = lib60870.CS101_ASDU_create(
                slave.al_params, False, CS101_COT_PERIODIC, 0, 1, False, False)
            io = lib60870.MeasuredValueScaled_create(
                None, 110, slave.scaled_value, IEC60870_QUALITY_GOOD)
            lib60870.CS101_ASDU_addInformationObject(new_asdu, io)
            lib60870.InformationObject_destroy(io)
            slave.enqueue_asdu(new_asdu)
            lib60870.CS101_ASDU_destroy(new_asdu)
            slave.scaled_value += 1
    except KeyboardInterrupt:
        pass
    
    # 停止从站
    slave.stop()
    print("CS104 slave stopped")

if __name__ == "__main__":
    example_usage()